package com.tanger.pay.alipay;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.alipay.api.*;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Description 支付宝支付处理类
 * @Author Hchenbin
 * @Date 2024-01-03 09:12
 * @Version 1.0
 */
@Slf4j
public class AliPayHelper {

    private static final String FORMAT = "JSON";
    private static final String CHARSET = "UTF-8";
    //签名方式
    private static final String SIGN_TYPE = "RSA2";

    /**
     * 支付响应
     * @param aliPay
     * @param resp
     */
    public static void payResponse(AliPayVO aliPay, HttpServletResponse resp) {
        try {
            String form = pay(aliPay);
            resp.setContentType("text/html;charset=" + CHARSET);
            resp.getWriter().write(form);// 直接将完整的表单html输出到页面
            resp.getWriter().flush();
            resp.getWriter().close();
        } catch (Exception e) {
            log.info("Failed to initiate payment！reason：{}", e.getMessage());
        }
    }

    /**
     * 支付
     * @param aliPay
     * @return
     */
    public static String pay(AliPayVO aliPay) {
        // 1. 创建Client，通用SDK提供的Client，负责调用支付宝的API
        AlipayClient alipayClient = new DefaultAlipayClient(
                AliPayConfig.gatewayUrl,
                AliPayConfig.appId,
                AliPayConfig.appPrivateKey,
                FORMAT, CHARSET,
                AliPayConfig.alipayPublicKey,
                SIGN_TYPE);

        // 2. 创建 Request并设置Request参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  // 发送请求的 Request类
        // 异步回调接口（POST请求）
        request.setNotifyUrl(aliPay.getNotifyUrl());
        JSONObject bizContent = new JSONObject();
        bizContent.set("out_trade_no", aliPay.getTradeNo());  // 我们自己生成的订单编号
        bizContent.set("total_amount", aliPay.getTotalAmount()); // 订单的总金额
        bizContent.set("subject", aliPay.getSubject());   // 支付的名称
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置
        request.setBizContent(bizContent.toString());

        // 执行请求，拿到响应的结果，返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return form;
    }

    /**
     * 支付-证书方式
     * @param aliPay
     * @return
     * @throws AlipayApiException
     */
    public static String alipayPayCert(AliPayVO aliPay) {
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(AliPayConfig.gatewayUrl);
        certAlipayRequest.setAppId(AliPayConfig.appId);
        certAlipayRequest.setPrivateKey(AliPayConfig.appPrivateKey);
        certAlipayRequest.setFormat(FORMAT);
        certAlipayRequest.setCharset(CHARSET);
        certAlipayRequest.setSignType(SIGN_TYPE);
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(AliPayConfig.appCertPath);
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(AliPayConfig.alipayCertPath);
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(AliPayConfig.alipayRootCertPath);
        try  {
            //构造client
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
            //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest ();
            //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(aliPay.getSubject());
            model.setSubject(aliPay.getSubject());
            model.setOutTradeNo(aliPay.getTradeNo());
            model.setTimeoutExpress("30m");
            model.setTotalAmount(aliPay.getTotalAmount()+"");
            model.setProductCode("QUICK_MSECURITY_PAY");
            request.setBizModel(model);
            request.setNotifyUrl(aliPay.getNotifyUrl());

            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute( request );
            //响应结果body可以直接给客户端请求，无需再做处理。
            return response.getBody();
        }  catch (AlipayApiException e ) {
            log.error("Pay Failed! reason: {}", e.getErrMsg());
        }
        return null;
    }

    /**
     * 回调,返回结果支撑订单状态变更
     * @param request
     * @return
     * @throws Exception
     */
    public static NotifyResult notify(HttpServletRequest request) {
        try {
            if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
                log.info("=========支付宝异步回调========");
                Map<String, String> params = new HashMap<>();
                Map<String, String[]> requestParams = request.getParameterMap();
                for (String name : requestParams.keySet()) {
                    params.put(name, request.getParameter(name));
                }

                String sign = params.get("sign");
                String content = AlipaySignature.getSignCheckContentV1(params);
                // 验证签名
                boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, AliPayConfig.alipayPublicKey, "UTF-8");
                // 支付宝验签
                if (checkSignature) {
                    // 回调返回结果以支撑订单状态变更
                    return NotifyResult.builder()
                            .subject(params.get("subject"))
                            .status(params.get("trade_status"))
                            .tradeNo(params.get("out_trade_no"))
                            .alipayTradeNo(params.get("trade_no"))
                            .buyerId(params.get("buyer_id"))
                            .totalAmount(Double.valueOf(params.get("total_amount")))
                            .payAmount(params.get("buyer_pay_amount"))
                            .payTime(params.get("gmt_payment"))
                            .build();
                }
            }
            return null;
        } catch (Exception e) {
            log.info("Callback failed! reason: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 退款
     * @param aliPay
     * @return
     * @throws AlipayApiException
     */
    public static AlipayTradeRefundResponse refund(AliPayVO aliPay) {
        try {
            // 1. 创建Client，通用SDK提供的Client，负责调用支付宝的API
            AlipayClient alipayClient = new DefaultAlipayClient(
                    AliPayConfig.gatewayUrl,
                    AliPayConfig.appId,
                    AliPayConfig.appPrivateKey,
                    FORMAT, CHARSET,
                    AliPayConfig.alipayPublicKey,
                    SIGN_TYPE);
            // 2. 创建 Request，设置参数
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.set("trade_no", aliPay.getAlipayTradeNo());  // 支付宝回调的订单流水号
            bizContent.set("refund_amount", aliPay.getTotalAmount());  // 订单的总金额
            bizContent.set("out_request_no", aliPay.getTradeNo());   //  我的订单编号

            // 返回参数选项，按需传入
            //JSONArray queryOptions = new JSONArray();
            //queryOptions.add("refund_detail_item_list");
            //bizContent.put("query_options", queryOptions);
            request.setBizContent(bizContent.toString());

            // 3. 执行请求
            return alipayClient.execute(request);
        } catch (AlipayApiException e) {
            log.error("Failed refund! reason: {}", e.getErrMsg());
            return null;
        }
    }

    /**
     * 提现
     * @param drawal
     * @return
     * @throws AlipayApiException
     */
    public static AlipayFundTransUniTransferResponse withdrawal(WithdrawalVO drawal) {
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setFormat(FORMAT);
        alipayConfig.setCharset(CHARSET);
        alipayConfig.setSignType(SIGN_TYPE);
        alipayConfig.setServerUrl(AliPayConfig.gatewayUrl);
        alipayConfig.setAppId(AliPayConfig.appId);
        alipayConfig.setPrivateKey(AliPayConfig.appPrivateKey);
        //证书信息
        alipayConfig.setAppCertPath(AliPayConfig.appCertPath);
        alipayConfig.setAlipayPublicCertPath(AliPayConfig.alipayCertPath);
        alipayConfig.setRootCertPath(AliPayConfig.alipayRootCertPath);
        // 构造client
        DefaultAlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(alipayConfig);
            AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
            AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
            Participant payeeInfo = new Participant();
            payeeInfo.setIdentity(drawal.getId());
            payeeInfo.setName(drawal.getName());
            payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
            model.setPayeeInfo(payeeInfo);
            model.setProductCode("TRANS_ACCOUNT_NO_PWD");
            model.setOrderTitle("提现");
            model.setOutBizNo(drawal.getTradeNo());
            //是否展示付款方别名
            model.setBusinessParams("{\"payer_show_name_use_alias\":\"true\"}");
            /*SignData signData = new SignData();
            signData.setOriOutBizNo("订单号");
            signData.setOriSignType("RSA2");
            signData.setOriSign("EqHFP0z4a9iaQ1ep==");
            signData.setOriCharSet("UTF-8");
            signData.setPartnerId("签名被授权方支付宝账号ID");
            signData.setOriAppId("2021000185629012");
            model.setSignData(signData);*/
            model.setRemark("提现");
//          model.setOriginalOrderId("20190620110075000006640000063056");
//          model.setPassbackParams("{\"merchantBizType\":\"peerPay\"}");
            model.setBizScene("DIRECT_TRANSFER");
            model.setTransAmount(drawal.getTotalAmount()+"");
            request.setBizModel(model);
            return alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            log.error("Failed withdrawal! reason: {}", e.getErrMsg());
            return null;
        }
    }

    /**
     * 自动取消到期订单
     */
    public void cancel () {
        // TODO 可使用quartz定时任务实现订单到期自动取消、
        //  timer、RabbitMQ死信队列、RocketMQ延迟消息、
        //  DelayQueue延迟队列、redission等多种方式实现
    }

    /**
     * 退款示例
     */
    public static void main(String... args) {
        //1.校验 7天无理由退款
        String now = DateUtil.now();
        // TODO 根据商户订单号获取订单信息
//        Orders orders = ordersMapper.getByNo(aliPay.getTraceNo());
        if (Objects.nonNull(new Object())) {
            // hutool工具类，判断时间间隔
            long between = DateUtil.between(DateUtil.parseDateTime("订单支付时间"), DateUtil.parseDateTime(now), DateUnit.DAY);
            if (between > 7) {
                log.error("该订单已超过7天，不支持退款");
            }
        }
        AlipayTradeRefundResponse resp = refund(new AliPayVO());
        //2.校验 退款结果
        if (resp.isSuccess()) {
            // TODO 3. 更新数据库状态
//            ordersMapper.updatePayState(aliPay.getTraceNo(), "已退款", now);
            log.info("OK");
            return;
        }
        //退款失败
        log.error("Failed! code:{}, message:{}",resp.getCode(), resp.getBody());
    }
}
